package org.ihelpuoo.weboo.util;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.ihelpuoo.lang.BooleanUtils;
import org.ihelpuoo.lang.ObjectUtils;
import org.ihelpuoo.lang.StringUtils;
import org.ihelpuoo.orm.IIIException;
import org.ihelpuoo.orm.ObjectRule;
import org.ihelpuoo.orm.filter.SQLFilter;
import org.ihelpuoo.parser.segment.CharSegment;
import org.ihelpuoo.parser.segment.Segment;
import org.ihelpuoo.weboo.module.ActionContext;

public class HttpQuerySQLFilter extends SQLFilter
{

	public HttpQuerySQLFilter(ActionContext context)
	{
		this.context = context;
		this.conditions = new LinkedList<ConditionItem>();
	}

	private ActionContext		context;
	private List<ConditionItem>	conditions;
	private String				orderby;

	public void setCondition(String s)
	{
		String[] ss = StringUtils.splitIgnoreBlank(s,";");
		if (ss == null)
		{
			conditions.clear();
			return;
		}
		for (int i = 0; i < ss.length; i++)
			conditions.add(new ConditionItem(ss[i]));

	}

	public void setOrderBy(String s) throws IIIException
	{
		if (null == s)
		{
			orderby = null;
			return;
		}
		CharSegment seg = new CharSegment(s);
		Iterator<String> it = seg.iterator();
		ObjectRule rule;
		try
		{
			rule = context.pojo().getRule(context.properties().getObjectType());
		}
		catch (ClassNotFoundException e)
		{
			throw new RuntimeException(e);
		}
		while (it.hasNext())
		{
			String key = it.next();
			if (key.charAt(0) == '@')
				seg.set(key,rule.getDBFieldName(key.substring(1)));
		}
		orderby = seg.toString();
	}

	@Override
	public CharSequence getOrderByString()
	{
		return orderby;
	}

	@Override
	public CharSequence getConditionString() throws IIIException
	{
		Iterator<ConditionItem> it = conditions.iterator();
		StringBuffer sb = new StringBuffer();
		while (it.hasNext())
		{
			ConditionItem ci = it.next();
			String s = ci.render(context);
			if (null != s)
				sb.append(s);
			if (sb.length() > 0 && it.hasNext())
				sb.append(" AND ");
		}
		return sb;
	}

	/**
	 * Store each condition item
	 */
	private class ConditionItem
	{
		private boolean	not;
		private String	head;
		private Segment	seg;

		ConditionItem(String s)
		{
			int pos = 0;
			if (s.charAt(0) == '?')
			{
				pos = s.indexOf('?',1);
				if (pos == -1)
					throw new RuntimeException("Invalid condition string: " + s);
				head = StringUtils.trim(s.substring(1,pos));
				if (head.charAt(0) == '!')
				{
					not = true;
					head = head.substring(1);
				}
				pos++;
			}
			seg = new CharSegment(s.substring(pos));
		}

		String render(ActionContext context) throws IIIException
		{
			boolean ava = BooleanUtils.isTrue(evalValue(context,head));
			if (null != head && (!ava ^ not))
				return null;
			Iterator<String> it = seg.iterator();
			ObjectRule rule;
			try
			{
				rule = context.pojo().getRule(context.properties().getObjectType());
			}
			catch (ClassNotFoundException e)
			{
				throw new RuntimeException(e);
			}
			while (it.hasNext())
			{
				String key = it.next();
				// get object in DB
				if (key.charAt(0) == '@')
					seg.set(key,rule.getDBFieldName(key.substring(1)));
				else
					seg.set(key,evalValue(context,key));

			}
			return seg.toString();
		}

		private Object evalValue(ActionContext context, String s)
		{
			if (s != null)
			{
				Object value = null;
				if (s.startsWith("param."))
					value = context.params().getStringTrimed(s.substring(6));
				else if (s.startsWith("session.account"))
				{
					String fn = s.substring(16);
					value = ObjectUtils.getFieldValue(context.getSession().getAccount(),fn);
				}
				return value;
			}
			return null;
		}
	}
}
